Pandas 사용 팁

pandas
Author

강신성

Published

2023-10-13

Pandas에서 유용하게 사용할 수 있는 여러가지 메소드들을 알아보자!

해당 포스트는 전북대학교 통계학과 최규빈 교수님의 강의내용을 토대로 재구성되었음을 알립니다.

1. 라이브러리 imports

import numpy as np
import pandas as pd
from plotnine import *

2. pabdas : transform column

A. lambda

B. map

C. s.apply(변환함수) | 원소들을 각각 변환


  • 변환함수 : 원래 형식을 보존하면서 원소들을 바꾸는 함수
  • 집계함수 : 벡터 -> 스칼라 (평균을 불러주는 함수 : [1,2,3,4,5] -> 3)

라고 하자.

df = pd.read_csv('https://raw.githubusercontent.com/guebin/DV2022/master/posts/FIFA23_official_data.csv')   ## DataFrame
s = df.Height   ## Series
s
0        189cm
1        179cm
2        172cm
3        181cm
4        172cm
         ...  
17655    190cm
17656    195cm
17657    190cm
17658    187cm
17659    186cm
Name: Height, Length: 17660, dtype: object

뒤에 cm가 붙어있는 범주형 자료로 저장되어있음.

s.apply(lambda x : int(x[:3])) ## 집계함수가 아닌 변환함수만 적용할 수 있음. 각 원소에 함수 적용.
##s.apply(lambda x : x[:3]).apply(int)    ## 연쇄적으로
##s.apply(lambda x : x[:3]).astype('int64')   ## astype() 이용
0        189
1        179
2        172
3        181
4        172
        ... 
17655    190
17656    195
17657    190
17658    187
17659    186
Name: Height, Length: 17660, dtype: int64

cm를 제거하고 포맷을 정수형으로 변경하였다.

### D. s.str, idx.str | string 오브젝트에만 사용할 수 있는 함수를 사용

df = pd.read_csv('https://raw.githubusercontent.com/guebin/DV2022/master/posts/FIFA23_official_data.csv')
s = df.Height
"180cm"[:3]
'180'
'180cm'.replace('cm','')
'180'

위와 같은 연산을 시리즈에 적용시키고 싶다.

s.str[:3]
##s.str.replace('cm', '')   ## 개별 문자열과 동일하게 메소드를 적용시켜도 된다.
0        189
1        179
2        172
3        181
4        172
        ... 
17655    190
17656    195
17657    190
17658    187
17659    186
Name: Height, Length: 17660, dtype: object

문자열의 메소드를 그대로 적용 가능

- 예시2 : 원소별로 isupper를 수행(대문자인지 판별)

_s = pd.Series(['A','B','C','d','e','F'])
_s
0    A
1    B
2    C
3    d
4    e
5    F
dtype: object
_s.str.isupper()
0     True
1     True
2     True
3    False
4    False
5     True
dtype: bool

- 예시3 : 원소별로 공백 제거(pd.Serise 뿐만 아니라 pd.index 자료형에도 사용가능)

df = pd.read_csv('https://raw.githubusercontent.com/guebin/DV2022/master/posts/FIFA23_official_data.csv')
idx = df.columns
idx.str.replace(' ', '')
Index(['ID', 'Name', 'Age', 'Photo', 'Nationality', 'Flag', 'Overall',
       'Potential', 'Club', 'ClubLogo', 'Value', 'Wage', 'Special',
       'PreferredFoot', 'InternationalReputation', 'WeakFoot', 'SkillMoves',
       'WorkRate', 'BodyType', 'RealFace', 'Position', 'Joined', 'LoanedFrom',
       'ContractValidUntil', 'Height', 'Weight', 'ReleaseClause', 'KitNumber',
       'BestOverallRating'],
      dtype='object')

- 쉽게 말해서 string데이터를 지닌 개체에 string에 사용할 수 있는 메소드를 사용할 수 있도록 하는 게 pandas의 str이라고 보면 된다.

E. s.astype() | 조건을 충족한 시리즈의 타입을 변경


- 예시1 : 원소의 타입을 변경

s = pd.Series(list('12345'))
s
0    1
1    2
2    3
3    4
4    5
dtype: object
s.astype(int)
##s.apply(int)
0    1
1    2
2    3
3    4
4    5
dtype: int64

- 예시2 : 원소의 타입을 변환한 이후 브로드캐스팅

s1 = pd.Series(list('12345'))
s2 = pd.Series([-1,-2,-3,-4,-5])
s1+s2
TypeError: ignored

Error : 형식이 달라 불가능

s1.astype(int) + s2
0    0
1    0
2    0
3    0
4    0
dtype: int64
s2.astype(str) + s1
0    -11
1    -22
2    -33
3    -44
4    -55
dtype: object

- 예시3 : 원소의 타입을 변환한 이후 브로드캐스팅(str)

df = pd.read_csv("https://raw.githubusercontent.com/guebin/DV2023/main/posts/titanic.csv")[:5]
df
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked logFare
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S 1.981001
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C 4.266662
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S 2.070022
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S 3.972177
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S 2.085672

위의 자료에서 Embarked열과 Pclass열을 사용하여 아래와 같은 New Feature를 만들어라.

Embarked Pclass New Feature
‘S’ 3 ‘S3’
‘C’ 1 ‘C1’
‘S’ 3 ‘S3’
‘S’ 1 ‘S1’
‘S’ 3 ‘S3’

둘다 문자열이면 단순히 +를 이용해 브로드캐스팅하면 되지만, 타입이 달라 불가하다.

df.Embarked + df.Pclass.apply(str)
##df.Embarked + df.Pclass.astype(str)
##df.Embarked + pd.Series(list(map(lambda x : str(x)), df.Pclass))
0    S3
1    C1
2    S3
3    S1
4    S3
dtype: object

### F. 컴프리헨션, lambda + map을 무시하지 말 것

- 예시1

df = pd.read_csv("https://raw.githubusercontent.com/guebin/DV2023/main/posts/titanic.csv")[:5]
df
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked logFare
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S 1.981001
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C 4.266662
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S 2.070022
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S 3.972177
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S 2.085672

위 자료에서 아래와 같은 변환을 하고 싶다면 apply만으로 사용하기에 부담이 된다.

\[ f(\text{sex}, \text{sibsp}) = \begin{cases} 0.7 + 0.25 \times \text{sibsp} & \text{if } \text{sex} = \text{'female'} \\ 0.2 + 0.15 \times \text{sibsp} & \text{otherwise} \end{cases} \]

list(map(lambda sex, sibsp : 0.7+0.25*sibsp if sex == 'female' else 0.2+0.15*sibsp, df.Sex, df.SibSp))
[0.35, 0.95, 0.7, 0.95, 0.2]
df.assign(Probablity = list(map(lambda sex, sibsp : 0.7+0.25*sibsp if sex == 'female' else 0.2+0.15*sibsp, df.Sex, df.SibSp)))
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked logFare Probablity
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S 1.981001 0.35
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C 4.266662 0.95
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S 2.070022 0.70
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S 3.972177 0.95
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S 2.085672 0.20

- 예시2

df = pd.read_csv("https://raw.githubusercontent.com/guebin/DV2023/main/posts/titanic.csv")[:5]
df
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked logFare
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S 1.981001
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C 4.266662
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S 2.070022
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S 3.972177
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S 2.085672

위의 자료에서 Name열을 아래와 같이 분리하는 작업을 수행하라.

title Name
0 Mr Owen Harris Braund
1 Mrs John Bradley (Florence Briggs Thayer) Cumings
2 Miss Laina Heikkinen
3 Mrs Jacques Heath (Lily May Peel) Futrelle
4 Mr William Henry Allen

- 풀이 1

df.Name.str.replace(', ','/').str.replace('. ','/').str.split('/')
0                            [Braund, Mr, Owen Harris]
1    [Cumings, Mrs, John Bradley (Florence Briggs T...
2                             [Heikkinen, Miss, Laina]
3       [Futrelle, Mrs, Jacques Heath (Lily May Peel)]
4                           [Allen, Mr, William Henry]
Name: Name, dtype: object
[[title, name + ' ' + f_name] for f_name, title, name in df.Name.str.replace(', ','/').str.replace('. ','/').str.split('/')]
[['Mr', 'Owen Harris Braund'],
 ['Mrs', 'John Bradley (Florence Briggs Thayer) Cumings'],
 ['Miss', 'Laina Heikkinen'],
 ['Mrs', 'Jacques Heath (Lily May Peel) Futrelle'],
 ['Mr', 'William Henry Allen']]

- 풀이 2 : 이중 컴프리헨션이 될까 해서 해봤는데… 되네?~(솔직히 안될 이유가 없긴 함, 리스트를 반환하는 거니까…)~

[[names[0], names[1] + ' ' + f_name] for f_name, names in [[f_name, names.split('. ')] for f_name, names in df.Name.str.split(', ')]]
[['Mr', 'Owen Harris Braund'],
 ['Mrs', 'John Bradley (Florence Briggs Thayer) Cumings'],
 ['Miss', 'Laina Heikkinen'],
 ['Mrs', 'Jacques Heath (Lily May Peel) Futrelle'],
 ['Mr', 'William Henry Allen']]
lists = [[names[0], names[1] + ' ' + f_name] for f_name, names in [[f_name, names.split('. ')] for f_name, names in df.Name.str.split(', ')]]
pd.DataFrame({'title' : np.array(lists)[:,0], 'Name' : np.array(lists)[:,1]})
title Name
0 Mr Owen Harris Braund
1 Mrs John Bradley (Florence Briggs Thayer) Cumings
2 Miss Laina Heikkinen
3 Mrs Jacques Heath (Lily May Peel) Futrelle
4 Mr William Henry Allen